package  de.tum.softwarengineering1.ws201112.team11.sudoku.gui;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;

public class SudokuTable extends JPanel implements TableModel, ActionListener {
    private static final long serialVersionUID = 1L;

    private int size;

    private boolean blockNotify = false;

    ArrayList<TableModelListener> listeners = new ArrayList<TableModelListener>();

    SudokuTable(int size) {
	if (Math.sqrt(size) * Math.sqrt(size) != size)
	    throw new IllegalArgumentException(
		    "Size must be a quadratic value!");
	this.size = size;
	setupGrid(size);
    }

    private void setupGrid(int size) {
	assert Math.sqrt(size) * Math.sqrt(size) == size;
	int boxSize = Double.valueOf(Math.sqrt(size)).intValue();
	GridBagLayout layout = new GridBagLayout();
	setLayout(layout);
	GridBagConstraints c = new GridBagConstraints();
	c.fill = GridBagConstraints.HORIZONTAL;
	JComboBox newCell;
	String[] comboValues = new String[size + 1];
	comboValues[0] = "";
	for (int i = 1; i <= size; i++) {
	    comboValues[i] = String.valueOf(i);
	}

	for (int i = 0; i < size; i++) {
	    for (int j = 0; j < size; j++) {
		newCell = new JComboBox(comboValues);
		newCell.setActionCommand(i + "," + j);
		newCell.addActionListener(this);
		c.gridx = j;
		c.gridy = i;
		Insets ins = new Insets(0, 0, 0, 0);
		if ((i + 1) % boxSize == 0)
		    ins.bottom = 2;
		else if (i % boxSize == 0)
		    ins.top = 2;
		if ((j + 1) % boxSize == 0)
		    ins.right = 2;
		else if (j % boxSize == 0)
		    ins.left = 2;
		c.insets = ins;
		layout.setConstraints(newCell, c);
		add(newCell);
	    }
	}
    }

    @Override
    public void addTableModelListener(TableModelListener l) {
	listeners.add(l);
    }

    @Override
    public Class<?> getColumnClass(int columnIndex) {
	return Integer.class;
    }

    @Override
    public int getColumnCount() {
	return size;
    }

    @Override
    public String getColumnName(int columnIndex) {
	return String.valueOf(columnIndex);
    }

    @Override
    public int getRowCount() {
	return size;
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
	JComboBox combo = (JComboBox) getComponent(getComboIndex(rowIndex,
		columnIndex));
	return combo.getSelectedIndex();
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
	// TODO Auto-generated method stub
	return false;
    }

    protected void notifyListeners(int row, int column) {
	if (blockNotify)
	    return;
	TableModelEvent event = new TableModelEvent(this, row, row, column);
	for (TableModelListener listener : listeners) {
	    listener.tableChanged(event);
	}
    }

    @Override
    public void removeTableModelListener(TableModelListener l) {
	listeners.remove(l);
    }

    @Override
    public void setValueAt(Object value, int line, int column) {
	JComboBox combo = (JComboBox) getComponent(getComboIndex(line, column));
	assert value instanceof Integer;
	blockNotify = true;
	combo.setSelectedIndex((Integer) value);
	blockNotify = false;
    }

    private int getComboIndex(int line, int column) {
	return size * line + column;
    }

    @Override
    public void actionPerformed(ActionEvent event) {
	assert event.getSource() instanceof JComboBox;

	int row, column;

	String[] lineColumn = event.getActionCommand().split(",");
	row = Integer.valueOf(lineColumn[0]);
	column = Integer.valueOf(lineColumn[1]);
	notifyListeners(row, column);
    }

    public void reset() {
	for (int i = 0; i < size; i++) {
	    for (int j = 0; j < size; j++) {
		releaseFixed(i, j);
		setValueAt(0, i, j);
	    }
	}

    }

    public void setFixed(int row, int col) {
	JComboBox box = (JComboBox) getComponent(getComboIndex(row, col));
	// box.setFocusable(false);
	box.setEnabled(false);
	// box.setPopupVisible(false);
	// box.setEditable(false);
	// box.setForeground(Color.BLUE);

    }

    public void releaseFixed(int row, int col) {
	JComboBox box = (JComboBox) getComponent(getComboIndex(row, col));
	box.setEnabled(true);
    }
}
